import logging
import datetime
from enum import Enum
from typing import Optional, cast, Any, List

from kopf import Body
from kubernetes.client.rest import ApiException

# 常量定义
GROUP = "example.com"
VERSION = "v1alpha1"
KIND = "Website"
PLURAL = "websites"
API_VERSION = f"{GROUP}/{VERSION}"


class WebsitePhase(Enum):
    """Website部署阶段"""
    PENDING = "Pending"
    CREATING = "Creating"
    RUNNING = "Running"
    FAILED = "Failed"
    TERMINATING = "Terminating"


class WebsiteConditionType(Enum):
    """Website状态条件类型"""
    DEPLOYMENT_READY = "DeploymentReady"
    SERVICE_READY = "ServiceReady"
    HEALTHY = "Healthy"


class ImagePullPolicy(Enum):
    """镜像拉取策略"""
    ALWAYS = "Always"
    IF_NOT_PRESENT = "IfNotPresent"
    NEVER = "Never"


class ServiceType(Enum):
    """服务类型"""
    CLUSTER_IP = "ClusterIP"
    NODE_PORT = "NodePort"
    LOAD_BALANCER = "LoadBalancer"


class ImageSpec:
    """镜像规格"""
    repository: Optional[str] = None
    tag: Optional[str] = None
    pull_policy: Optional[ImagePullPolicy] = None

    def parse(self, spec: dict, prefix: str) -> None:
        self.repository = spec.get("repository")
        self.tag = spec.get("tag", "latest")
        self.pull_policy = ImagePullPolicy(spec.get("pullPolicy", "IfNotPresent"))

    def validate(self, logger) -> None:
        if not self.repository:
            raise ValueError(f"repository is required for ImageSpec in {prefix}")

        if not self.tag:
            raise ValueError(f"tag is required for ImageSpec in {prefix}")


class ServiceSpec:
    """服务规格"""
    type: Optional[ServiceType] = None
    port: Optional[int] = None
    target_port: Optional[int] = None

    def parse(self, spec: dict, prefix: str) -> None:
        self.type = ServiceType(spec.get("type", "ClusterIP"))
        self.port = spec.get("port", 80)
        self.target_port = spec.get("targetPort", 8080)

    def validate(self, logger) -> None:
        if not self.port or self.port <= 0:
            raise ValueError(f"port must be a positive integer in {prefix}")

        if not self.target_port or self.target_port <= 0:
            raise ValueError(f"targetPort must be a positive integer in {prefix}")


class HealthCheckSpec:
    """健康检查规格"""
    enabled: bool = False
    path: Optional[str] = None
    port: Optional[int] = None
    initial_delay_seconds: int = 30
    period_seconds: int = 10
    timeout_seconds: int = 5
    failure_threshold: int = 3
    success_threshold: int = 1

    def parse(self, spec: dict, prefix: str) -> None:
        self.enabled = spec.get("enabled", False)
        if self.enabled:
            self.path = spec.get("path", "/health")
            self.port = spec.get("port", 8080)
            self.initial_delay_seconds = spec.get("initialDelaySeconds", 30)
            self.period_seconds = spec.get("periodSeconds", 10)
            self.timeout_seconds = spec.get("timeoutSeconds", 5)
            self.failure_threshold = spec.get("failureThreshold", 3)
            self.success_threshold = spec.get("successThreshold", 1)

    def validate(self, logger) -> None:
        if self.enabled:
            if not self.path:
                raise ValueError(f"path is required when healthCheck is enabled in {prefix}")
            if not self.port or self.port <= 0:
                raise ValueError(f"port must be a positive integer when healthCheck is enabled in {prefix}")


class ResourceSpec:
    """资源规格"""
    requests: dict = {}
    limits: dict = {}

    def parse(self, spec: dict, prefix: str) -> None:
        self.requests = spec.get("requests", {})
        self.limits = spec.get("limits", {})

    def validate(self, logger) -> None:
        # 资源验证逻辑可以在这里添加
        pass


class EnvVarSpec:
    """环境变量规格"""
    name: Optional[str] = None
    value: Optional[str] = None
    value_from: Optional[dict] = None

    def parse(self, spec: dict, prefix: str) -> None:
        self.name = spec.get("name")
        self.value = spec.get("value")
        self.value_from = spec.get("valueFrom")

    def validate(self, logger) -> None:
        if not self.name:
            raise ValueError(f"name is required for EnvVarSpec in {prefix}")
        
        if not self.value and not self.value_from:
            raise ValueError(f"either value or valueFrom is required for EnvVarSpec in {prefix}")


class WebsiteSpec:
    """Website规格"""
    name: Optional[str] = None
    replicas: int = 1
    image: Optional[ImageSpec] = None
    service: Optional[ServiceSpec] = None
    health_check: Optional[HealthCheckSpec] = None
    resources: Optional[ResourceSpec] = None
    env: Optional[List[EnvVarSpec]] = None
    custom_html: Optional[str] = None

    def __init__(self, namespace: str, name: str, spec: dict):
        self.namespace = namespace
        self.name = name
        self.spec = spec
        self.load(spec)

    def load(self, spec: dict) -> None:
        self.name = spec.get("name")
        self.replicas = spec.get("replicas", 1)
        
        # 解析镜像规格
        self.image = ImageSpec()
        self.image.parse(spec.get("image", {}), "spec.image")
        
        # 解析服务规格
        self.service = ServiceSpec()
        self.service.parse(spec.get("service", {}), "spec.service")
        
        # 解析健康检查规格
        self.health_check = HealthCheckSpec()
        self.health_check.parse(spec.get("healthCheck", {}), "spec.healthCheck")
        
        # 解析资源规格
        self.resources = ResourceSpec()
        self.resources.parse(spec.get("resources", {}), "spec.resources")
        
        # 解析环境变量
        env_list = spec.get("env", [])
        self.env = []
        for i, env_item in enumerate(env_list):
            env_spec = EnvVarSpec()
            env_spec.parse(env_item, f"spec.env[{i}]")
            self.env.append(env_spec)
        
        # 解析自定义HTML内容
        self.custom_html = spec.get("customHtml")

    def validate(self, logger) -> None:
        if not self.name:
            raise ValueError("name is required for WebsiteSpec")
        
        if self.replicas < 0:
            raise ValueError("replicas must be non-negative")
        
        self.image.validate(logger)
        self.service.validate(logger)
        self.health_check.validate(logger)
        self.resources.validate(logger)
        
        for env_var in self.env:
            env_var.validate(logger)


class Website:
    """Website Kubernetes资源接口"""

    def __init__(self, body: Body):
        self._obj: Body = body
        self._spec: Optional[WebsiteSpec] = None

    @property
    def metadata(self) -> dict:
        return self._obj.get('metadata', {})

    @property
    def namespace(self) -> str:
        return self.metadata['namespace']

    @property
    def name(self) -> str:
        return self.metadata['name']

    @property
    def annotations(self) -> dict:
        return self.metadata.get('annotations', {})

    @property
    def uid(self) -> str:
        return self.metadata['uid']

    @property
    def is_deleting(self) -> bool:
        return "deletionTimestamp" in self.metadata and self.metadata["deletionTimestamp"] is not None

    @property
    def spec(self) -> dict:
        return self._obj['spec']

    @property
    def labels(self) -> dict:
        return self.metadata.get('labels', {})

    @property
    def status(self) -> dict:
        return self._obj.get('status', {})

    def __str__(self):
        return f'{self.namespace}/{self.name}'

    def __repr__(self):
        return f'<Website {self.name}>'

    def parse_spec(self) -> None:
        self._spec = WebsiteSpec(self.namespace, self.name, self.spec)

    def get_spec(self) -> WebsiteSpec:
        if not self._spec:
            self.parse_spec()
            assert self._spec is not None, "Spec should be parsed before accessing it."
        return self._spec

    def self_ref(self, field_path: Optional[str] = None) -> dict:
        ref = {
            'apiVersion': API_VERSION,
            'kind': KIND,
            'name': self.name,
            'namespace': self.namespace,
            'uid': self.uid,
            'resourceVersion': self.metadata['resourceVersion']
        }

        if field_path:
            ref['fieldPath'] = field_path

        return ref

    def event_ref(self, field_path: Optional[str] = None) -> dict:
        """Return object reference for Kubernetes events."""
        ref = {
            'apiVersion': API_VERSION,
            'kind': KIND,
            'name': self.name,
            'namespace': self.namespace,
            'uid': self.uid
        }

        if field_path:
            ref['fieldPath'] = field_path

        return ref

    def self_logging(self, logger) -> None:
        logger.info(f'Website: {self.namespace}/{self.name}')
        logger.info(f'\tUID: {self.uid}')
        
        spec = self.get_spec()
        logger.info(f'\tName: {spec.name}')
        logger.info(f'\tReplicas: {spec.replicas}')
        logger.info(f'\tImage: {spec.image.repository}:{spec.image.tag}')
        logger.info(f'\tService Type: {spec.service.type.value}')
        logger.info(f'\tService Port: {spec.service.port}')
        logger.info(f'\tHealth Check Enabled: {spec.health_check.enabled}')
        
        if spec.env:
            logger.info(f'\tEnvironment Variables: {len(spec.env)}')
            for env_var in spec.env:
                logger.info(f'\t\t{env_var.name}: {"***" if env_var.value_from else env_var.value}')

    def _get_status_field(self, field: str) -> Any:
        return cast(str, self.status.get(field))

    def get_create_time(self) -> Optional[datetime.datetime]:
        dt = self._get_status_field("createTime")
        if dt:
            return datetime.datetime.fromisoformat(dt.rstrip("Z"))
        return None

    def get_phase(self) -> Optional[WebsitePhase]:
        phase_str = self._get_status_field("phase")
        if phase_str:
            try:
                return WebsitePhase(phase_str)
            except ValueError:
                return None
        return None

    def ready(self, logger: logging.Logger) -> bool:
        """Check if the Website is ready by verifying:
        1. Creation time exists
        2. Phase is Running
        3. All conditions are met

        Args:
            logger: Logger instance to use for logging
        
        Returns:
            bool: True if all conditions are met, False otherwise
        """
        # Check creation time exists
        if not self.get_create_time():
            logger.debug(f"{self.namespace}/{self.name} - Creation time not found")
            return False

        # Check phase is Running
        phase = self.get_phase()
        if not phase or phase != WebsitePhase.RUNNING:
            logger.debug(f"{self.namespace}/{self.name} - Phase is not Running: {phase}")
            return False

        # Check conditions
        conditions = self.status.get("conditions", [])
        for condition in conditions:
            if condition.get("status") != "True":
                logger.debug(f"{self.namespace}/{self.name} - Condition {condition.get('type')} is not True")
                return False

        logger.debug(f"{self.namespace}/{self.name} - All conditions met, website is ready")
        return True

    def update_status(self, status: dict) -> None:
        """更新Website状态"""
        try:
            from kubernetes.client import CustomObjectsApi
            from kubernetes import client
            
            custom_api = CustomObjectsApi()
            
            # 获取当前Website对象
            website = custom_api.get_namespaced_custom_object(
                group=GROUP,
                version=VERSION,
                plural=PLURAL,
                namespace=self.namespace,
                name=self.name
            )

            # 更新状态
            website['status'] = status

            # 应用更新
            custom_api.patch_namespaced_custom_object_status(
                group=GROUP,
                version=VERSION,
                plural=PLURAL,
                namespace=self.namespace,
                name=self.name,
                body=website
            )

            # 更新本地对象
            self._obj = website

        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Failed to update status for Website {self.namespace}/{self.name}: {e}")

    def error(self, action: str, reason: str, msg: str) -> None:
        """记录错误事件"""
        import logging
        logger = logging.getLogger(__name__)
        logger.error(f"Website {self.namespace}/{self.name} - {action}: {reason} - {msg}")

    def info(self, action: str, reason: str, msg: str) -> None:
        """记录信息事件"""
        import logging
        logger = logging.getLogger(__name__)
        logger.info(f"Website {self.namespace}/{self.name} - {action}: {reason} - {msg}")

    def warn(self, action: str, reason: str, msg: str) -> None:
        """记录警告事件"""
        import logging
        logger = logging.getLogger(__name__)
        logger.warning(f"Website {self.namespace}/{self.name} - {action}: {reason} - {msg}")
